#include "data_acq_task.h"
#include <future>
#include <protocol/xcom_handler.h>
#include <settings/config_parser.h>
namespace data_acq {
DataAcqTask::DataAcqTask(const std::string &name)
	: name_(name)
{
}

void DataAcqTask::LoadProtocol(const std::string &filePath)
{
	HTELINK_TRACE("load protocol file, %s", filePath);
	if (!protocol::XComHandler::GetXComInstance()->LoadProtocol(filePath)) {
		HTELINK_LOG_ERR("protocol load failed, %s", filePath);
	}
}

void DataAcqTask::LoadChannels()
{
	channelTasks_.clear();
	dbms::DbmsChannel dbmsChannel;
	dbmsChannel.Get([this](const dbms::DeviceChannel_t &chn) -> void {
		std::shared_ptr<ChannelTask> channelTask =
			std::make_shared<ChannelTask>(chn);
		channelTask->Subscribe(subscribeCallback_);
		channelTask->SubscribeException(subscribeExceptionCallback_);
		channelTasks_.push_back(channelTask);
	});
}
void DataAcqTask::StartAll()
{
	for (auto &task : channelTasks_) {
		task->Start();
	}
}
void DataAcqTask::StopAll()
{
	for (auto &task : channelTasks_) {
		task->Stop();
	}
}
void DataAcqTask::Subscribe(SubscribeCallback subscrib)
{
	subscribeCallback_ = subscrib;
	for (auto &task : channelTasks_) {
		task->Subscribe(subscrib);
	}
}
void DataAcqTask::SubscribeException(SubscribeExceptionCallback subscribe)
{
	subscribeExceptionCallback_ = subscribe;
	for (auto &task : channelTasks_) {
		task->SubscribeException(subscribe);
	}
}
std::vector<uint8_t> DataAcqTask::OnDeviceCommand(
	int32_t channelId, const std::vector<uint8_t> &cmd)
{
	auto it = std::find_if(channelTasks_.begin(), channelTasks_.end(),
		[&](const std::shared_ptr<ChannelTask> &task) {
			return channelId == task->ID();
		});
	if (it == channelTasks_.end()) {
		HTELINK_LOG_ERR("less for this channel %d", channelId);
		return std::vector<uint8_t>();
	}
	return (*it)->DownlinkWork(cmd);
}
dbms::AcqData_t DataAcqTask::OnDeviceCommand(
	const std::string &deviceId, const std::vector<dbms::AcqItem_t> &items)
{
	auto it = std::find_if(channelTasks_.begin(), channelTasks_.end(),
		[&](const std::shared_ptr<ChannelTask> &task) {
			return task->HasDevice(deviceId);
		});
	if (it == channelTasks_.end()) {
		HTELINK_LOG_ERR("less for this device %s", deviceId);
		return dbms::AcqData_t();
	}
	auto promise = std::make_shared<std::promise<dbms::AcqData_t> >();
	std::future<dbms::AcqData_t> future = promise->get_future();
	(*it)->CommitImmedAcq(
		deviceId, items,
		[promise](const dbms::Device_t &, const dbms::AcqData_t &data) -> bool {
			promise->set_value(data);
			return true;
		},
		[&](const dbms::Device_t &, const std::string &) {
			dbms::AcqData_t data;
			promise->set_value(data);
		});
	std::future_status status =
		future.wait_for(std::chrono::milliseconds(1500));
	if (status != std::future_status::ready) {
		HTELINK_LOG_ERR(
			"timeout to immed acq, status: %d", static_cast<int32_t>(status));
		return dbms::AcqData_t();
	}
	return future.get();
}
} // namespace data_acq